﻿namespace EasyToolkit.BindingTemplates.Context
{
    using System;
    using EasyToolkit.BindingTemplates.Definitions.Binding;
    using EasyToolkit.Tools.Extensions;
    using EasyToolkit.Tools.Log;

    public class BindingContextItem : IBindingContextItem
    {
        #region attributes and properties
        private ILogger log = Logger.Instance;

        public IBindingContextElement Parent
        { get; private set; }

        public string Name
        { get; private set; }

        public IBindingDefinition BindingDefinition
        { get; private set; }

        protected bool isResolved;
        protected object resolvedBinding;
        public object ResolvedBinding
        {
            get
            {
                if (! isResolved)
                    ResolveBinding();
                return resolvedBinding;
            }
        }

        public object DataSource
        { get { return Parent.DataSource; } }

        public bool CanNotify
        { get; protected set; }

        public bool IsDisposed
        { get; private set; }
        #endregion

        #region .ctors
        public BindingContextItem(IBindingContextElement parent, IBindingDefinition bindingDefinition)
        {
            Parent = parent;
            BindingDefinition = bindingDefinition;
            CanNotify = false;
            Name = BindingDefinition == null ? string.Empty : BindingDefinition.BindingExpression;
        }
        #endregion

        #region methods
        public void Init()
        {
            ResolveBinding();

            if (Parent.Parent.SortAndFilter != null && BindingDefinition.IsBoundWithData)
            {
                BindingTypeProperty property = Parent.Parent.TemplateDefinition.BindingType.PropertyByName[BindingDefinition.Name];
                property.SetMethod.Invoke(Parent.Element, new object[] { ResolvedBinding });
            }
        }
        
        virtual public object ResolveBinding()
        {
            try
            {
                isResolved = true;
                resolvedBinding = BindingDefinition == null ? null : BindingDefinition.ResolveBinding(this.DataSource);
                return resolvedBinding;
            }
            catch (Exception ex)
            {
                string message = string.Format("Can't resolve binding for 'BindingDefinition' '{0}': {1}", Name, ex.Message.EmptyIfNull());
                log.LogException(LogType.Error, ex, message);
                return "##Binding Error##";
            }
        }

        virtual public bool UpdateDataSource(object data, out object retValue)
        {
            if (this.BindingDefinition != null)
            {
                retValue = this.BindingDefinition.UpdateDataSource(this.DataSource, data);
                return true;
            }
            else
            { 
                retValue = null;
                return false;
            }
        }

        public void Dispose()
        {
            if (!IsDisposed)
            {
                IsDisposed = true;
                RealDispose();
            }
        }

        public virtual void RealDispose()
        {}
        #endregion
    }
}
